package com.kgc.novel.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kgc.novel.common.Res;
import com.kgc.novel.constants.JwtConstant;
import com.kgc.novel.domain.entity.BookAdmin;
import com.kgc.novel.domain.param.BookAdminParam;
import com.kgc.novel.service.admin.BookAdminService;
import com.kgc.novel.util.JwtUtil;
import com.kgc.novel.util.MD5Util;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;


/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author:lklklklk
 * @since 2023-03-21
 */

@RestController
@RequestMapping("/admin")
@Slf4j
@Api(tags = "管理员接口")
public class BookAdminController {
    @Resource
    private BookAdminService bookAdminService;

    @Resource
    private JwtUtil jwtUtil;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @PostMapping("/login")
    @ApiOperation("用户登录")
    public Res login(@RequestBody BookAdminParam bookAdminParam) {
        return bookAdminService.login(bookAdminParam);
    }

    @GetMapping("/list")
    @ApiOperation("获取用户信息分页列表")
    public Res getUserList(BookAdminParam bookAdminParam) {
        LambdaQueryWrapper<BookAdmin> wrapper = Wrappers.lambdaQuery(BookAdmin.class)
                .orderByDesc(BookAdmin::getAdminName);
        Page<BookAdmin> page = new Page<>(bookAdminParam.getPageNo(), bookAdminParam.getPageSize());
        Page<BookAdmin> usersPage = bookAdminService.page(page, wrapper);
        return Res.returnData(usersPage.getRecords(), usersPage.getTotal());
    }

    @GetMapping("/userInfo")
    @ApiOperation("获取用户信息")
    public Res getUserInfo(HttpServletRequest request) {
        String token = Optional.ofNullable(request).map(r -> r.getHeader("token")).orElse("");
        token = token.replaceFirst("Bearer ", "");
        String userId = jwtUtil.getUserIdFromToken(token);
        BookAdmin bookAdmin = bookAdminService.getById(userId);
        bookAdmin.setPassword(null);
        return bookAdmin == null ? Res.returnErrMsg("获取用户数据失败") : Res.returnData(bookAdmin);
    }

    /*
      如果用户一直在操作，当jwt颁发的token令牌（用户凭证）到了过期时间需要刷新token（refresh_token）,
      除非用户长时间没有进行任何操作的话，则需要强制重新登录
     */
    @ApiOperation("刷新Token")
    @GetMapping("/refresh_token")
    public Res refreshToken(@RequestHeader(value = "refreshToken") String accessToken) {
        accessToken = accessToken.replaceFirst(JwtConstant.PREFIX, "");
        if (StringUtils.isEmpty(accessToken)) {
            return Res.returnTokenErr("the token is null");
        }

        // 对Token解签名，并验证Token是否过期
        boolean isJwtNotValid = jwtUtil.isTokenExpired(accessToken);
        if (isJwtNotValid) {
            return Res.returnTokenErr("the access token is invalid");
        }

        // 验证 token 里面的 userId 是否为空
        String userId = jwtUtil.getUserIdFromToken(accessToken);
        String username = jwtUtil.getUserNameFromToken(accessToken);
        if (StringUtils.isEmpty(userId)) {
            return Res.returnTokenErr("the access token is invalid");
        }

        // 这里为了保证 refreshToken 只能用一次，刷新后，会从 redis 中删除。
        // 如果用的不是 redis 中的 refreshToken 进行刷新令牌，则不能刷新。
        // 如果使用 redis 中已过期的 refreshToken 也不能刷新令牌。
        boolean isRefreshTokenNotExisted = jwtUtil.isRefreshTokenNotExistCache(accessToken);
        if (isRefreshTokenNotExisted) {
            return Res.returnTokenErr("the refresh token is invalid");
        }
        Map<String, Object> tokenMap = jwtUtil.refreshTokenAndGenerateToken(userId, username);
        BookAdmin admin = bookAdminService.getById(userId);
//        admin.setTokenType("Bearer Token");
        admin.setAccessToken("Bearer " + tokenMap.get("access_token").toString());
        admin.setRefreshToken("Bearer " + tokenMap.get("refresh_token").toString());
        admin.setExpireIn(Long.valueOf(tokenMap.get("expire_in").toString()));
        return Res.returnData(admin);
    }

    @GetMapping("/logout")
    @ApiOperation("退出登录")
    public Res logout(HttpServletRequest request) {
        String token = request.getHeader("token");
        Boolean delete = redisTemplate.delete(token);
        return Boolean.TRUE.equals(delete) ? Res.returnMsg("退出成功！") : Res.returnErrMsg("退出失败！");
    }

    @DeleteMapping("/del/{userId}")
    @ApiOperation("删除用户")
    public Res deleteUsers(@PathVariable(value = "userId") Integer userId) {
        return bookAdminService.removeById(userId) ? Res.returnMsg("删除用户数据成功！") : Res.returnMsg("删除用户数据失败！");
    }

    @DeleteMapping("/delBatch")
    @ApiOperation("批量删除用户")
    public Res deleteUsersBatch(@RequestBody List<Integer> ids) {
        return bookAdminService.removeBatchByIds(ids) ? Res.returnMsg("批量删除用户数据成功！") : Res.returnMsg("批量删除用户数据失败！");
    }

    @PostMapping("/updPassword")
    @ApiOperation("修改用户密码")
    public Res updatePassword(@RequestBody BookAdminParam bookAdminParam) {
        LambdaUpdateWrapper<BookAdmin> wrapper = Wrappers.lambdaUpdate(BookAdmin.class)
                .set(StringUtils.isNotBlank(bookAdminParam.getPassword()), BookAdmin::getPassword, MD5Util.getStrMD5(bookAdminParam.getPassword()))
                .eq(Objects.nonNull(bookAdminParam.getUserId()), BookAdmin::getAdminId, bookAdminParam.getUserId());
        return bookAdminService.update(wrapper) ? Res.returnMsg("修改用户密码成功") : Res.returnErrMsg("修改用户密码失败");
    }

    @PostMapping("/saveOrUpdate")
    @ApiOperation("保存或修改用户信息")
    public Res addOrUpdate(@RequestBody BookAdmin bookAdmin) {
        String id = bookAdmin.getAdminId();
        if (id == null) {
            bookAdmin.setPassword(MD5Util.getStrMD5(bookAdmin.getPassword()));
        }
        if (bookAdminService.saveOrUpdate(bookAdmin))
            return id == null ? Res.returnMsg("添加用户信息成功！") : Res.returnMsg("修改用户信息成功！");
        return id == null ? Res.returnErrMsg("添加用户信息失败！") : Res.returnErrMsg("修改用户信息失败！");
    }

}
